// 会话管理器

import { BaseManager } from '../core/BaseManager';
import { RedisClient } from '../core/RedisClient';
import {
  SessionData,
  SessionInfo,
  SessionConfig,
  SessionStats,
  SessionCleanupResult,
} from '../types/session';
import { KeyGenerator } from '../utils/keyGenerator';
import { v4 as uuidv4 } from 'uuid';

export class SessionManager extends BaseManager {
  private userKeyGenerator: KeyGenerator;
  private config: SessionConfig;

  constructor(client: RedisClient, config: Partial<SessionConfig> = {}) {
    super(client, new KeyGenerator({ prefix: 'session' }));
    this.userKeyGenerator = new KeyGenerator({ prefix: 'user' });

    this.config = {
      defaultTtl: 3600, // 1 hour
      maxSessions: 10,
      extendOnActivity: true,
      trackLocation: false,
      trackDevice: true,
      ...config,
    };
  }

  /**
   * 创建会话
   */
  async createSession(
    userId: string,
    data: Partial<SessionData> = {},
    ttl?: number
  ): Promise<string> {
    this.validateRequired({ userId });

    const sessionId = uuidv4();
    const sessionKey = this.keyGenerator.session(sessionId);
    const userSessionsKey = this.userKeyGenerator.userSessions(userId);
    const sessionTtl = ttl ?? this.config.defaultTtl;

    const sessionData: SessionData = {
      userId,
      deviceId: data.deviceId,
      userAgent: data.userAgent,
      ipAddress: data.ipAddress,
      createdAt: new Date(),
      lastActivity: new Date(),
      expiresAt: new Date(Date.now() + sessionTtl * 1000),
      data: data.data ?? {},
    };

    const startTime = this.now();

    try {
      // 检查用户会话数量限制
      await this.enforceSessionLimit(userId);

      // 创建会话
      await this.setValue(sessionKey, sessionData, sessionTtl);

      // 添加到用户会话集合
      await this.execute('sadd', userSessionsKey, sessionId);
      await this.setExpire(userSessionsKey, sessionTtl);

      this.logMetric('session.create', this.now() - startTime, true, {
        userId,
        sessionId,
        ttl: sessionTtl,
      });

      return sessionId;
    } catch (error) {
      this.logMetric('session.create', this.now() - startTime, false, { userId, error });
      throw this.formatError(error, 'Failed to create session');
    }
  }

  /**
   * 获取会话
   */
  async getSession(sessionId: string): Promise<SessionData | null> {
    this.validateRequired({ sessionId });

    const sessionKey = this.keyGenerator.session(sessionId);
    const startTime = this.now();

    try {
      const sessionData = await this.getValue<SessionData>(sessionKey);

      if (!sessionData) {
        this.logMetric('session.get', this.now() - startTime, false, {
          sessionId,
          reason: 'not_found',
        });
        return null;
      }

      // 检查是否过期
      if (sessionData.expiresAt && sessionData.expiresAt < new Date()) {
        await this.destroySession(sessionId);
        this.logMetric('session.get', this.now() - startTime, false, {
          sessionId,
          reason: 'expired',
        });
        return null;
      }

      // 更新最后活动时间
      if (this.config.extendOnActivity) {
        sessionData.lastActivity = new Date();
        const ttl = await this.getTtl(sessionKey);
        if (ttl > 0) {
          await this.setValue(sessionKey, sessionData, ttl);
        }
      }

      this.logMetric('session.get', this.now() - startTime, true, { sessionId });
      return sessionData;
    } catch (error) {
      this.logMetric('session.get', this.now() - startTime, false, { sessionId, error });
      throw this.formatError(error, 'Failed to get session');
    }
  }

  /**
   * 更新会话
   */
  async updateSession(sessionId: string, data: Partial<SessionData>): Promise<void> {
    this.validateRequired({ sessionId });

    const sessionKey = this.keyGenerator.session(sessionId);
    const startTime = this.now();

    try {
      const sessionData = await this.getValue<SessionData>(sessionKey);

      if (!sessionData) {
        throw new Error('Session not found');
      }

      // 更新数据
      const updatedData: SessionData = {
        ...sessionData,
        ...data,
        lastActivity: new Date(),
      };

      const ttl = await this.getTtl(sessionKey);
      await this.setValue(sessionKey, updatedData, ttl > 0 ? ttl : undefined);

      this.logMetric('session.update', this.now() - startTime, true, { sessionId });
    } catch (error) {
      this.logMetric('session.update', this.now() - startTime, false, { sessionId, error });
      throw this.formatError(error, 'Failed to update session');
    }
  }

  /**
   * 销毁会话
   */
  async destroySession(sessionId: string): Promise<void> {
    this.validateRequired({ sessionId });

    const sessionKey = this.keyGenerator.session(sessionId);
    const startTime = this.now();

    try {
      // 获取会话数据以获取用户ID
      const sessionData = await this.getValue<SessionData>(sessionKey);

      // 删除会话
      await this.deleteKeys(sessionKey);

      // 从用户会话集合中移除
      if (sessionData) {
        const userSessionsKey = this.userKeyGenerator.userSessions(sessionData.userId);
        await this.execute('srem', userSessionsKey, sessionId);
      }

      this.logMetric('session.destroy', this.now() - startTime, true, { sessionId });
    } catch (error) {
      this.logMetric('session.destroy', this.now() - startTime, false, { sessionId, error });
      throw this.formatError(error, 'Failed to destroy session');
    }
  }

  /**
   * 获取用户所有会话
   */
  async getUserSessions(userId: string): Promise<SessionInfo[]> {
    this.validateRequired({ userId });

    const userSessionsKey = this.userKeyGenerator.userSessions(userId);
    const sessionIds = await this.execute<string[]>('smembers', userSessionsKey);

    const sessions: SessionInfo[] = [];

    for (const sessionId of sessionIds) {
      try {
        const sessionData = await this.getSession(sessionId);

        if (sessionData) {
          sessions.push({
            sessionId,
            userId: sessionData.userId,
            deviceId: sessionData.deviceId,
            deviceType: this.extractDeviceType(sessionData.userAgent),
            location: this.extractLocation(sessionData.ipAddress),
            createdAt: sessionData.createdAt,
            lastActivity: sessionData.lastActivity,
            isActive: this.isSessionActive(sessionData),
          });
        }
      } catch {
        // 忽略无效会话
      }
    }

    return sessions;
  }

  /**
   * 销毁用户所有会话
   */
  async destroyUserSessions(userId: string): Promise<void> {
    this.validateRequired({ userId });

    const userSessionsKey = this.userKeyGenerator.userSessions(userId);
    const sessionIds = await this.execute<string[]>('smembers', userSessionsKey);

    const pipeline = this.createPipeline();

    for (const sessionId of sessionIds) {
      const sessionKey = this.keyGenerator.session(sessionId);
      pipeline.del(sessionKey);
    }

    pipeline.del(userSessionsKey);
    await pipeline.exec();
  }

  /**
   * 延长会话
   */
  async extendSession(sessionId: string, ttl: number): Promise<void> {
    this.validateRequired({ sessionId });
    this.validateNumber(ttl, 'ttl', 1);

    const sessionKey = this.keyGenerator.session(sessionId);
    const sessionData = await this.getValue<SessionData>(sessionKey);

    if (!sessionData) {
      throw new Error('Session not found');
    }

    sessionData.expiresAt = new Date(Date.now() + ttl * 1000);
    sessionData.lastActivity = new Date();

    await this.setValue(sessionKey, sessionData, ttl);
  }

  /**
   * 清理过期会话
   */
  async cleanupExpiredSessions(): Promise<SessionCleanupResult> {
    const pattern = this.keyGenerator.pattern('*');
    const sessionKeys = await this.getKeys(pattern);

    const result: SessionCleanupResult = {
      expiredSessions: 0,
      inactiveSessions: 0,
      totalCleaned: 0,
      errors: [],
    };

    for (const sessionKey of sessionKeys) {
      try {
        const sessionData = await this.getValue<SessionData>(sessionKey);

        if (!sessionData) {
          continue;
        }

        let shouldClean = false;

        // 检查是否过期
        if (sessionData.expiresAt && sessionData.expiresAt < new Date()) {
          result.expiredSessions++;
          shouldClean = true;
        }

        // 检查是否长时间不活跃
        const inactiveThreshold = new Date(Date.now() - 24 * 60 * 60 * 1000); // 24小时
        if (sessionData.lastActivity < inactiveThreshold) {
          result.inactiveSessions++;
          shouldClean = true;
        }

        if (shouldClean) {
          const sessionId = sessionKey.split(':').pop();
          if (sessionId) {
            await this.destroySession(sessionId);
            result.totalCleaned++;
          }
        }
      } catch (error) {
        result.errors.push({
          sessionId: sessionKey,
          error: error as Error,
        });
      }
    }

    return result;
  }

  /**
   * 获取会话统计信息
   */
  async getStats(): Promise<SessionStats> {
    const pattern = this.keyGenerator.pattern('*');
    const sessionKeys = await this.getKeys(pattern);

    let activeSessions = 0;
    let expiredSessions = 0;
    let totalDuration = 0;
    const userCounts: Record<string, number> = {};
    const deviceCounts: Record<string, number> = {};

    for (const sessionKey of sessionKeys) {
      try {
        const sessionData = await this.getValue<SessionData>(sessionKey);

        if (!sessionData) {
          continue;
        }

        if (this.isSessionActive(sessionData)) {
          activeSessions++;

          // 统计用户会话数
          userCounts[sessionData.userId] = (userCounts[sessionData.userId] ?? 0) + 1;

          // 统计设备类型
          const deviceType = this.extractDeviceType(sessionData.userAgent);
          if (deviceType) {
            deviceCounts[deviceType] = (deviceCounts[deviceType] ?? 0) + 1;
          }

          // 计算会话持续时间
          const duration = sessionData.lastActivity.getTime() - sessionData.createdAt.getTime();
          totalDuration += duration;
        } else {
          expiredSessions++;
        }
      } catch {
        // 忽略无效会话
      }
    }

    const topUsers = Object.entries(userCounts)
      .sort(([, a], [, b]) => b - a)
      .slice(0, 10)
      .map(([userId, sessionCount]) => ({ userId, sessionCount }));

    return {
      totalSessions: sessionKeys.length,
      activeSessions,
      expiredSessions,
      averageSessionDuration: activeSessions > 0 ? totalDuration / activeSessions : 0,
      topUsers,
      deviceBreakdown: deviceCounts,
    };
  }

  /**
   * 强制执行会话数量限制
   */
  private async enforceSessionLimit(userId: string): Promise<void> {
    const sessions = await this.getUserSessions(userId);

    if (sessions.length >= this.config.maxSessions) {
      // 删除最旧的会话
      const oldestSessions = sessions
        .sort((a, b) => a.lastActivity.getTime() - b.lastActivity.getTime())
        .slice(0, sessions.length - this.config.maxSessions + 1);

      for (const session of oldestSessions) {
        await this.destroySession(session.sessionId);
      }
    }
  }

  /**
   * 检查会话是否活跃
   */
  private isSessionActive(sessionData: SessionData): boolean {
    if (sessionData.expiresAt && sessionData.expiresAt < new Date()) {
      return false;
    }
    return true;
  }

  /**
   * 从User-Agent提取设备类型
   */
  private extractDeviceType(userAgent?: string): string | undefined {
    if (!userAgent) return undefined;

    if (/Mobile|Android|iPhone|iPad/.test(userAgent)) {
      return 'mobile';
    } else if (/Tablet/.test(userAgent)) {
      return 'tablet';
    } else {
      return 'desktop';
    }
  }

  /**
   * 从IP地址提取位置信息（简化实现）
   */
  private extractLocation(ipAddress?: string): string | undefined {
    // 实际项目中可以使用GeoIP库
    return ipAddress ? 'Unknown' : undefined;
  }
}
